//Linux C plus plus file
/************************************************************************
 *
 *
 *       			FileName:confMgr.cpp
 *
 *         			Author.wzj
 *
 *       			Email:345517039@qq.com
 *
 *      	    		Create:2017-06-22 23:35:54
 *
 *      		    	Description:-
 *
 *
 *************************************************************************/
#include "confMgr.h"
#include "utils.h"

/**
 * @brief 
 */
confMgr * confMgr::instance = NULL;


/**
 * @brief 
 */
const char *confKey[]=
{	
	"IP_ADDRESS",
	"PORT",
	"PROCESS_THREAD_NUM",
	"LISTEN_THREAD_NUM",
	"THREAD_PRIORITY",
	"THREAD_STACK_SIZE",
	"THREAD_SCHEDULE_POLICY",
	"ACCESS_LOG_PATH",
	"ERROR_LOG_PATH",
	"WRITE_LOG_LEVEL",
	"CMD_1",
	"CMD_2",
	"CMD_3",
	"CMD_4",
	"CMD_5",
	"CMD_6",
	"CMD_7",
	"CMD_8",
	"CMD_9",
	NULL
};


/**
 * @brief 
 */
const char * configOption[]=
{
	"SYSTEM",
	"THREAD",
	"LOG",
	"CMD",
	NULL
};



/**
 * @brief 
 *
 * @return 
 */
confMgr * confMgr::getInstance(){
	if( NULL != instance){
		return instance;
	}
	else
	{
		return new confMgr();
	}
}


/**
 * @brief 
 *
 * @param path
 *
 * @return 
 */
int confMgr::init(const char *path){
	mem.init(SYSTEM_LEVEL);
	readConfFile(path);
	return RET::SUCCESS;
}



/**
 * @brief 获取相应配置域的值
 *
 * @param type
 * @param arg
 * @param conf
 *
 * @return 
 */
int confMgr::getConfValue(int type, void *arg, confMgr *conf)
{
	struct log_conf_st * logconf = NULL;
	struct server_conf_st *serconf = NULL;
	std::multimap<int, int>::iterator it;
	struct configmgr_st confopt = conf->getConfOpt(); //获取相应的配
	switch(type)
	{
		case SYSTEM_CONFIG:
			{
				serconf = (struct server_conf_st *)arg;
			}
			break;
		case THREAD_CONFIG:
			{
				serconf = (struct server_conf_st *)arg;			
			}
			break;
		case LOG_CONFIG:
			{
				logconf = (struct log_conf_st *)arg;
			}
			break;
		default:
			return RET::FAIL;
	}
	it = confopt.keymap.find(type);
	std::multimap<int, char *>::iterator iter; //迭代器二;
	if ( it != confopt.keymap.end()){
		for(size_t i = 0; i != confopt.keymap.count(type); i++, it++ ){
			iter = confopt.confmap.find(it->second);
			if ( iter == confopt.confmap.end()){
				//
				return RET::FAIL;
			}
			size_t count =  confopt.confmap.count(it->second);
			switch(it->second){
			case LISTEN_IP_ADDR:
				for ( size_t i = 0; i != count; i++, iter++){
					serconf->ipaddr.push_back(iter->second);
				}
				serconf->ipaddrcount = count;
				break;
			case LISTEN_PORT:
				for ( size_t i = 0; i != count ; i++, iter++){
					serconf->portset.push_back(iter->second);
				}
				serconf->portcount = count;
				break;
			case PROCESS_THREAD_NUM:
				if ( iter->second != 0) 
				{
					serconf->processThreadNum = atoi(iter->second);
				} else {
					//error;
				}
				break;
			case LISTEN_THREAD_NUM:
				if ( iter->second != 0)
				{
					serconf->listenThreadNum = atoi(iter->second);
				} else {
					//error;
				}
				break;
			case THREAD_PRIORITY:
				break;
			case THREAD_STACK_SIZE:
				break;
			case THREAD_SCHEDULE_POLICY:
				break;
			case ACCESS_LOG_PATH:
				{
					logconf->pAccessLogPath=strdup(iter->second);
					DEBUG_TRACE(2,("[ CONFIG ]ACCESS LOG PATH:%s\n", logconf->pAccessLogPath));
				}
				break;
			case ERROR_LOG_PATH:
				{
					logconf->pErrorLogPath=strdup(iter->second);
					DEBUG_TRACE(2,("[ CONFIG ]ERROR LOG PATH:%s\n", logconf->pErrorLogPath));
				}
				break;
			case WRITE_LOG_LEVEL:
				{
					logconf->iWriteLogLevel = atoi(iter->second);
					DEBUG_TRACE(2,("[ CONFIG ]WRITE LOG LEVEL:%d\n", logconf->iWriteLogLevel));
				}
				break;
			default:
				return RET::FAIL;
			}
		}		    
	} else {
		return RET::FAIL; //没有找到;
	}
	return RET::SUCCESS;
}




/**
 * @brief 
 *
 * @param path
 *
 * @return 
 */
int confMgr::readConfFile(const char * path){
	char *fileName = NULL;
	assert(path!=NULL);
	//(1).先遍历目标路径看有没有后缀名为.conf的配置文件
	DIR *dir = opendir(path);
	if ( NULL == dir ){
		//打印错误;
	}
	struct dirent *st = NULL;
	//遍历当前的文件夹路径;
	while((st=readdir(dir))!= NULL){
		if((0==strncmp(st->d_name, "..",strlen("..")))||(0==strncmp(st->d_name, ".",strlen(".")))){
			continue;
		}
		if( 0 == strncmp(st->d_name, CONFMGR::CONFIGFILENAME, CONFMGR::CONFIGFILENAMELEN)){
			fileName = st->d_name;
			break;
		}
	}
	//打开读取配置;
	conf.configname = (char *)mem.allocateMemFromMempool(strlen(fileName));
	if ( !conf.configname ){
		return RET::FAIL;
	}
	memcpy(conf.configname, fileName, strlen(fileName));
	conf.file = fopen(conf.configname,"r+");
	if( conf.file == NULL ){
		//打印错误 并且写入错误日志;
		return RET::FAIL;
	}
#define BUFSIZE 100
	char buf[BUFSIZE];
	buf[0]='\0';
	char temp[BUFSIZE];
	temp[0] = '\0';
	while(fgets(buf,BUFSIZE,conf.file)!=NULL){
		if(buf[0]=='\n'|| buf[0]=='#')
			continue;
		formatReadFromConf(buf, temp);
		getConfigKeyAndValue(temp);
	}
	return RET::SUCCESS;
}


/**
 * @brief 
 *
 * @param buf
 * @param temp
 *
 * @return 
 */
int confMgr::formatReadFromConf(char *buf, char *temp){
	assert(buf!=NULL&&temp != NULL);
	char *p = buf;
	char *start = NULL;
	while(*p){
		if(NULL == start && (isspace(*p)||!isprint(*p))){
			p++;
			continue;
		}else{
			if(start == NULL){
				start = p;
			}else{
				if(start && (isspace(*p)||!isprint(*p))){
					*p = '\0';
					sprintf(temp+strlen(temp), "%s",start);
					start = NULL;
				}
			}
		}
		p++;
	}
	buf[0]='\0';
	if(temp[0]=='\0')
		return RET::FAIL;
	return RET::SUCCESS;
}


/**
 * @brief 
 *
 * @param buf
 *
 * @return 
 */
int confMgr::getConfigKeyAndValue(char *buf){
	assert(buf!=NULL);
	static int keyindex = -1;
	char *ptemp = buf;
	char *start = NULL;
	char *pos = NULL;
	pos = strstr(buf, "=");
	if(!pos){
		while(*ptemp){
			if(*ptemp == '['){
				start = ++ptemp;
				continue;
			}else if(*ptemp== ']'){
				*ptemp='\0';
				break;
			}
			ptemp++;
		}
		if(start){
			//识别为配置域;
			keyindex=setConfigKey(start);
		}
	}else{
		size_t len = pos - buf;
		char *value = ++pos;
		if(!*value){
			buf[0]='\0';
			return RET::FAIL;
		}else{

			setOptionConfigKeyAndValue(buf,value,len, keyindex);
		}
	}
	buf[0]='\0';
	return RET::SUCCESS;
}


/**
 * @brief 
 *
 * @param option
 *
 * @return 
 */
int confMgr::setConfigKey(char *option){
	if ( NULL == option){
		return RET::FAIL;
	}
	int ret  = -1;
	int index = SYSTEM_CONFIG;
	for(;configOption[index];){
		ret = strncmp(option, configOption[index], strlen(option));
		if(ret == 0){
			return index;
		}
		index++;
	}
	return RET::FAIL;
}


/**
 * @brief 
 *
 * @param option
 * @param value
 * @param len
 * @param keyindex
 *
 * @return 
 */
int confMgr::setOptionConfigKeyAndValue(char *option, char *value, size_t len, int keyindex){
	assert(option!=NULL && value!=NULL);
	std::vector< char *> port;
	int ret  = -1;
	int index = LISTEN_IP_ADDR;
	for(;confKey[index]; index++){
		ret = strncmp(option,confKey[index], len);
		if(ret == 0){
			switch(index)
			{
			case LISTEN_IP_ADDR:
				conf.keymap.insert(std::pair<int, int>(keyindex, LISTEN_IP_ADDR));					    
				conf.confmap.insert(std::pair<int, char *>(LISTEN_IP_ADDR, strdup(value)));
				return RET::SUCCESS;
			case LISTEN_PORT:
				ret = Utils::isPort(value,port);
				if(ret == RET::FAIL){
					return RET::FAIL;
				}
				conf.keymap.insert(std::pair<int, int>(keyindex, LISTEN_PORT));
				for(size_t i = 0; i < port.size(); i++){
					conf.confmap.insert(std::pair<int, char *>(LISTEN_PORT, strdup(port[i])));
				}
				return RET::SUCCESS;
			case PROCESS_THREAD_NUM:					
				conf.keymap.insert(std::pair<int, int>(keyindex, PROCESS_THREAD_NUM));					    
				conf.confmap.insert(std::pair<int, char *>(PROCESS_THREAD_NUM, strdup(value)));
				break;
			case LISTEN_THREAD_NUM:
				conf.keymap.insert(std::pair<int, int>(keyindex, LISTEN_THREAD_NUM));					    
				conf.confmap.insert(std::pair<int, char *>(LISTEN_THREAD_NUM, strdup(value)));
				return RET::SUCCESS;
			case THREAD_PRIORITY:	
				conf.keymap.insert(std::pair<int, int>(keyindex, THREAD_PRIORITY));					    
				conf.confmap.insert(std::pair<int, char *>(THREAD_PRIORITY, strdup(value)));
				return RET::SUCCESS;
			case THREAD_STACK_SIZE:
				conf.keymap.insert(std::pair<int, int>(keyindex, THREAD_STACK_SIZE));					    
				conf.confmap.insert(std::pair<int, char *>(THREAD_STACK_SIZE, strdup(value)));
				return RET::SUCCESS;
			case THREAD_SCHEDULE_POLICY:
				conf.keymap.insert(std::pair<int, int>(keyindex, THREAD_SCHEDULE_POLICY));					    
				conf.confmap.insert(std::pair<int, char *>(THREAD_SCHEDULE_POLICY, strdup(value)));
				return RET::SUCCESS;
			case ACCESS_LOG_PATH:
				conf.keymap.insert(std::pair<int, int>(keyindex, ACCESS_LOG_PATH));					    
				conf.confmap.insert(std::pair<int, char *>(ACCESS_LOG_PATH, strdup(value)));
				return RET::SUCCESS;
			case ERROR_LOG_PATH:
				conf.keymap.insert(std::pair<int, int>(keyindex, ERROR_LOG_PATH));					    
				conf.confmap.insert(std::pair<int, char *>(ERROR_LOG_PATH, strdup(value)));
				return RET::SUCCESS;
			case WRITE_LOG_LEVEL:
				conf.keymap.insert(std::pair<int, int>(keyindex, WRITE_LOG_LEVEL));					    
				conf.confmap.insert(std::pair<int, char *>(WRITE_LOG_LEVEL, strdup(value)));
				return RET::SUCCESS;
			case CMD_1:
			case CMD_2:
			case CMD_3:
			case CMD_4:
			case CMD_5:
			case CMD_6:
			case CMD_7:
			case CMD_8:
			case CMD_9:
				cmd.insertCmdTreeNode(index,strdup(value));
				return RET::SUCCESS;
			default:
				{
					DEBUG_TRACE(2,("[ WARN ]UNKNOWN CMD INDEX!\n"));
					//打印一下;
					return RET::FAIL;
				}
			}
		}
	}
	//参数合法性的检查;
	return RET::SUCCESS;
}




